#include "DotSceneLoader.h"
#include "tinyxml.h"
#include "Ogre.h"

using namespace std;
using namespace Ogre;

void DotSceneLoader::parseDotScene(const String &SceneName, const String &groupName, SceneManager *yourSceneMgr,bool physics,NxOgre::Scene* physScene,Critter::RenderSystem* physRenderSys, SceneNode *pAttachNode, const String &sPrependNode)
{
	String msg = "[DotSceneLoader] Loading scene: "+SceneName;
	LogManager::getSingleton().logMessage(msg);
	// set up shared object values
	m_sGroupName = groupName;
	mSceneMgr = yourSceneMgr;
	m_bPhysics=physics;
	m_pPhysRenderSys=physRenderSys;
	m_pPhysScene=physScene;

	m_sPrependNode = sPrependNode;
	staticObjects.clear();
	dynamicObjects.clear();

	TiXmlDocument   *XMLDoc = 0;
	TiXmlElement   *XMLRoot;

	try
	{
		// Strip the path
		Ogre::String basename, path;
		Ogre::StringUtil::splitFilename(SceneName, basename, path);

		DataStreamPtr pStream = ResourceGroupManager::getSingleton().
			openResource( basename, groupName );

		//DataStreamPtr pStream = ResourceGroupManager::getSingleton().
		//	openResource( SceneName, groupName );

		String data = pStream->getAsString();
		// Open the .scene File
		XMLDoc = new TiXmlDocument();
		XMLDoc->Parse( data.c_str() );
		pStream->close();
		pStream.setNull();

		if( XMLDoc->Error() )
		{
			//We'll just log, and continue on gracefully
			LogManager::getSingleton().logMessage("[DotSceneLoader] The TiXmlDocument reported an error");
			delete XMLDoc;
			return;
		}
	}
	catch(...)
	{
		//We'll just log, and continue on gracefully
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error creating TiXmlDocument");
		delete XMLDoc;
		return;
	}

	// Validate the File
	XMLRoot = XMLDoc->RootElement();
	if( String( XMLRoot->Value()) != "scene"  ) {
		LogManager::getSingleton().logMessage( "[DotSceneLoader] Error: Invalid .scene File. Missing <scene>" );
		delete XMLDoc;
		return;
	}

	// figure out where to attach any nodes we create
	mAttachNode = pAttachNode;
	if(!mAttachNode)
		mAttachNode = mSceneMgr->getRootSceneNode();

	// Process the scene
	processScene(XMLRoot);

	// Close the XML File
	delete XMLDoc;
}

void DotSceneLoader::processScene(TiXmlElement *XMLRoot)
{
	// Process the scene parameters
	String version = getAttrib(XMLRoot, "formatVersion", "unknown");

	String message = "[DotSceneLoader] Parsing dotScene file with version " + version;
	if(XMLRoot->Attribute("ID"))
		message += ", id " + String(XMLRoot->Attribute("ID"));
	if(XMLRoot->Attribute("sceneManager"))
		message += ", scene manager " + String(XMLRoot->Attribute("sceneManager"));
	if(XMLRoot->Attribute("minOgreVersion"))
		message += ", min. Ogre version " + String(XMLRoot->Attribute("minOgreVersion"));
	if(XMLRoot->Attribute("author"))
		message += ", author " + String(XMLRoot->Attribute("author"));

	LogManager::getSingleton().logMessage(message);

	TiXmlElement *pElement;

	// Process nodes (?)
	pElement = XMLRoot->FirstChildElement("nodes");
	if(pElement)
		processNodes(pElement);

	// Process externals (?)
	pElement = XMLRoot->FirstChildElement("externals");
	if(pElement)
		processExternals(pElement);

	// Process environment (?)
	pElement = XMLRoot->FirstChildElement("environment");
	if(pElement)
		processEnvironment(pElement);

	// Process terrain (?)
	pElement = XMLRoot->FirstChildElement("terrain");
	if(pElement)
		processTerrain(pElement);

	// Process userDataReference (?)
	pElement = XMLRoot->FirstChildElement("userDataReference");
	if(pElement)
		processUserDataReference(pElement);

	// Process octree (?)
	pElement = XMLRoot->FirstChildElement("octree");
	if(pElement)
		processOctree(pElement);

	// Process light (?)
	pElement = XMLRoot->FirstChildElement("light");
	if(pElement)
		processLight(pElement);

	// Process camera (?)
	pElement = XMLRoot->FirstChildElement("camera");
	if(pElement)
		processCamera(pElement);
}

void DotSceneLoader::processNodes(TiXmlElement *XMLNode)
{
	TiXmlElement *pElement;

	// Process node (*)
	pElement = XMLNode->FirstChildElement("node");
	while(pElement)
	{
		processNode(pElement);
		pElement = pElement->NextSiblingElement("node");
	}

	// Process position (?)
	pElement = XMLNode->FirstChildElement("position");
	if(pElement)
	{
		mAttachNode->setPosition(parseVector3(pElement));
		mAttachNode->setInitialState();
	}

	// Process rotation (?)
	pElement = XMLNode->FirstChildElement("rotation");
	if(pElement)
	{
		mAttachNode->setOrientation(parseQuaternion(pElement));
		mAttachNode->setInitialState();
	}

	// Process scale (?)
	pElement = XMLNode->FirstChildElement("scale");
	if(pElement)
	{
		mAttachNode->setScale(parseVector3(pElement));
		mAttachNode->setInitialState();
	}
}

void DotSceneLoader::processExternals(TiXmlElement *XMLNode)
{
	//! @todo Implement this
}

void DotSceneLoader::processEnvironment(TiXmlElement *XMLNode)
{
	TiXmlElement *pElement;

	// Process fog (?)
	pElement = XMLNode->FirstChildElement("fog");
	if(pElement)
		processFog(pElement);

	// Process skyBox (?)
	pElement = XMLNode->FirstChildElement("skyBox");
	if(pElement)
		processSkyBox(pElement);

	// Process skyDome (?)
	pElement = XMLNode->FirstChildElement("skyDome");
	if(pElement)
		processSkyDome(pElement);

	// Process skyPlane (?)
	pElement = XMLNode->FirstChildElement("skyPlane");
	if(pElement)
		processSkyPlane(pElement);

	// Process clipping (?)
	pElement = XMLNode->FirstChildElement("clipping");
	if(pElement)
		processClipping(pElement);

	// Process colourAmbient (?)
	pElement = XMLNode->FirstChildElement("colourAmbient");
	if(pElement)
		mSceneMgr->setAmbientLight(parseColour(pElement));

	// Process colourBackground (?)
	//! @todo Set the background colour of all viewports (RenderWindow has to be provided then)
	pElement = XMLNode->FirstChildElement("colourBackground");
	if(pElement)
		;//mSceneMgr->set(parseColour(pElement));

	// Process userDataReference (?)
	pElement = XMLNode->FirstChildElement("userDataReference");
	if(pElement)
		processUserDataReference(pElement);
}

void DotSceneLoader::processTerrain(TiXmlElement *XMLNode)
{
	/*std::string terrainConfig;

	String worldTexture = getAttrib(XMLNode, "WorldTexture");
	if (worldTexture.size() != 0)
	{
		terrainConfig += "WorldTexture=";
		terrainConfig += worldTexture;
		terrainConfig += "\n";
	}

	String detailTexture = getAttrib(XMLNode, "DetailTexture");
	if (detailTexture.size() != 0)
	{
		terrainConfig += "DetailTexture=";
		terrainConfig += detailTexture;
		terrainConfig += "\n";
	}

	String detailTile = getAttrib(XMLNode, "DetailTile");
	if (detailTile.size() != 0)
	{
		terrainConfig += "DetailTile=";
		terrainConfig += detailTile;
		terrainConfig += "\n";
	}

	String pageSource = getAttrib(XMLNode, "PageSource");
	if (pageSource.size() != 0)
	{
		terrainConfig += "PageSource=";
		terrainConfig += pageSource;
		terrainConfig += "\n";
	}

	String heightmapImage = getAttrib(XMLNode, "Heightmap.image");
	if (heightmapImage.size() != 0)
	{
		terrainConfig += "Heightmap.image=";
		terrainConfig += heightmapImage;
		terrainConfig += "\n";
	}

	String heightmapRawSize = getAttrib(XMLNode, "Heightmap.raw.size");
	if (heightmapRawSize.size() != 0)
	{
		terrainConfig += "Heightmap.raw.size=";
		terrainConfig += heightmapRawSize;
		terrainConfig += "\n";
	}

	String heightmapRawBpp = getAttrib(XMLNode, "Heightmap.raw.bpp");
	if (heightmapRawBpp.size() != 0)
	{
		terrainConfig += "Heightmap.raw.bpp=";
		terrainConfig += heightmapRawBpp;
		terrainConfig += "\n";
	}

	String pageSize = getAttrib(XMLNode, "PageSize");
	if (pageSize.size() != 0)
	{
		terrainConfig += "PageSize=";
		terrainConfig += pageSize;
		terrainConfig += "\n";
	}

	String tileSize = getAttrib(XMLNode, "TileSize");
	if (tileSize.size() != 0)
	{
		terrainConfig += "TileSize=";
		terrainConfig += tileSize;
		terrainConfig += "\n";
	}

	String maxPixelError = getAttrib(XMLNode, "MaxPixelError");
	if (maxPixelError.size() != 0)
	{
		terrainConfig += "MaxPixelError=";
		terrainConfig += maxPixelError;
		terrainConfig += "\n";
	}

	String pageWorldX = getAttrib(XMLNode, "PageWorldX");
	if (pageWorldX.size() != 0)
	{
		terrainConfig += "PageWorldX=";
		terrainConfig += pageWorldX;
		terrainConfig += "\n";
	}

	String pageWorldZ = getAttrib(XMLNode, "PageWorldZ");
	if (pageWorldZ.size() != 0)
	{
		terrainConfig += "PageWorldZ=";
		terrainConfig += pageWorldZ;
		terrainConfig += "\n";
	}

	String maxHeight = getAttrib(XMLNode, "MaxHeight");
	if (maxHeight.size() != 0)
	{
		terrainConfig += "MaxHeight=";
		terrainConfig += maxHeight;
		terrainConfig += "\n";
	}

	String maxMipMapLevel = getAttrib(XMLNode, "MaxMipMapLevel");
	if (maxMipMapLevel.size() != 0)
	{
		terrainConfig += "MaxMipMapLevel=";
		terrainConfig += maxMipMapLevel;
		terrainConfig += "\n";
	}

	String vertexNormals = getAttrib(XMLNode, "VertexNormals");
	if (vertexNormals.size() != 0)
	{
		terrainConfig += "VertexNormals=";
		terrainConfig += vertexNormals;
		terrainConfig += "\n";
	}

	String vertexColors = getAttrib(XMLNode, "VertexColors");
	if (vertexColors.size() != 0)
	{
		terrainConfig += "VertexColors=";
		vertexColors += vertexColors;
		terrainConfig += "\n";
	}

	String useTriStrips = getAttrib(XMLNode, "UseTriStrips");
	if (useTriStrips.size() != 0)
	{
		terrainConfig += "UseTriStrips=";
		terrainConfig += useTriStrips;
		terrainConfig += "\n";
	}

	String vertexProgramMorph = getAttrib(XMLNode, "VertexProgramMorph");
	if (vertexProgramMorph.size() != 0)
	{
		terrainConfig += "VertexProgramMorph=";
		terrainConfig += vertexProgramMorph;
		terrainConfig += "\n";
	}

	String morphLODFactorParamName = getAttrib(XMLNode, "MorphLODFactorParamName");
	if (morphLODFactorParamName.size() != 0)
	{
		terrainConfig += "MorphLODFactorParamName=";
		terrainConfig += morphLODFactorParamName;
		terrainConfig += "\n";
	}

	String morphLODFactorParamIndex = getAttrib(XMLNode, "MorphLODFactorParamIndex");
	if (morphLODFactorParamIndex.size() != 0)
	{
		terrainConfig += "MorphLODFactorParamIndex=";
		terrainConfig += morphLODFactorParamIndex;
		terrainConfig += "\n";
	}

	String lodMorphStart = getAttrib(XMLNode, "LODMorphStart");
	if (lodMorphStart.size() != 0)
	{
		terrainConfig += "LODMorphStart=";
		terrainConfig += lodMorphStart;
		terrainConfig += "\n";
	}

	void *pMem = OGRE_ALLOC_T(unsigned char, terrainConfig.length()+1, MEMCATEGORY_GENERAL);
	memset(pMem, 0, terrainConfig.length()+1);
	memcpy(pMem, terrainConfig.c_str(), terrainConfig.length() + 1);
	DataStreamPtr pStr(new Ogre::MemoryDataStream(pMem, terrainConfig.length() + 1, true));

	this->mSceneMgr->setWorldGeometry(pStr);*/
}

void DotSceneLoader::processUserDataReference(TiXmlElement *XMLNode, SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processOctree(TiXmlElement *XMLNode)
{
	//! @todo Implement this
}

void DotSceneLoader::processLight(TiXmlElement *XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");

	// Create the light
	Light *pLight = mSceneMgr->createLight(name);
	if(pParent)
		pParent->attachObject(pLight);

	String sValue = getAttrib(XMLNode, "type");
	if(sValue == "point")
		pLight->setType(Light::LT_POINT);
	else if(sValue == "directional")
		pLight->setType(Light::LT_DIRECTIONAL);
	else if(sValue == "spot")
		pLight->setType(Light::LT_SPOTLIGHT);
	else if(sValue == "radPoint")
		pLight->setType(Light::LT_POINT);

	pLight->setVisible(getAttribBool(XMLNode, "visible", true));
	pLight->setCastShadows(getAttribBool(XMLNode, "castShadows", true));

	TiXmlElement *pElement;

	// Process position (?)
	pElement = XMLNode->FirstChildElement("position");
	if(pElement)
		pLight->setPosition(parseVector3(pElement));

	// Process normal (?)
	pElement = XMLNode->FirstChildElement("normal");
	if(pElement)
		pLight->setDirection(parseVector3(pElement));

	// Process colourDiffuse (?)
	pElement = XMLNode->FirstChildElement("colourDiffuse");
	if(pElement)
		pLight->setDiffuseColour(parseColour(pElement));

	// Process colourSpecular (?)
	pElement = XMLNode->FirstChildElement("colourSpecular");
	if(pElement)
		pLight->setSpecularColour(parseColour(pElement));

	// Process lightRange (?)
	pElement = XMLNode->FirstChildElement("lightRange");
	if(pElement)
		processLightRange(pElement, pLight);

	// Process lightAttenuation (?)
	pElement = XMLNode->FirstChildElement("lightAttenuation");
	if(pElement)
		processLightAttenuation(pElement, pLight);

	// Process userDataReference (?)
	pElement = XMLNode->FirstChildElement("userDataReference");
	if(pElement)
		;//processUserDataReference(pElement, pLight);
}

void DotSceneLoader::processCamera(TiXmlElement *XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");
	Real fov = getAttribReal(XMLNode, "fov", 45);
	Real aspectRatio = getAttribReal(XMLNode, "aspectRatio", 1.3333);
	String projectionType = getAttrib(XMLNode, "projectionType", "perspective");

	// Find an existing cmaera
	Camera *pCamera = mSceneMgr->getCamera(name);

	if (pCamera == NULL)
	{
		// Create the camera
		Camera *pCamera = mSceneMgr->createCamera(name);
		if(pParent)
			pParent->attachObject(pCamera);
	}

	// Set the field-of-view
	//! @todo Is this always in degrees?
	pCamera->setFOVy(Ogre::Radian(Ogre::Math::DegreesToRadians(fov)));
	//pCamera->setFOVy(Ogre::Radian(fov));

	// Set the aspect ratio
	pCamera->setAspectRatio(aspectRatio);

	// Set the projection type
	if(projectionType == "perspective")
		pCamera->setProjectionType(PT_PERSPECTIVE);
	else if(projectionType == "orthographic")
		pCamera->setProjectionType(PT_ORTHOGRAPHIC);

	TiXmlElement *pElement;

	// Process clipping (?)
	pElement = XMLNode->FirstChildElement("clipping");
	if(pElement)
	{
		Real nearDist = getAttribReal(pElement, "near");
		pCamera->setNearClipDistance(nearDist);

		Real farDist =  getAttribReal(pElement, "far");
		pCamera->setFarClipDistance(farDist);
	}

	// Process position (?)
	pElement = XMLNode->FirstChildElement("position");
	if(pElement)
		pCamera->setPosition(parseVector3(pElement));
	else
		pCamera->setPosition(pParent->getPosition());

	// Process rotation (?)
	pElement = XMLNode->FirstChildElement("rotation");
	if(pElement)
		pCamera->setOrientation(parseQuaternion(pElement));
	else
		pCamera->setOrientation(pParent->getOrientation());

	pElement = XMLNode->FirstChildElement("lookAt");
	if(pElement)
		pCamera->lookAt(parseVector3(pElement));

	// Process normal (?)
	pElement = XMLNode->FirstChildElement("normal");
	if(pElement)
		;//!< @todo What to do with this element?

	// Process lookTarget (?)
	pElement = XMLNode->FirstChildElement("lookTarget");
	if(pElement)
		;//!< @todo Implement the camera look target

	// Process trackTarget (?)
	pElement = XMLNode->FirstChildElement("trackTarget");
	if(pElement)
		;//!< @todo Implement the camera track target

	// Process userDataReference (?)
	pElement = XMLNode->FirstChildElement("userDataReference");
	if(pElement)
		;//!< @todo Implement the camera user data reference
}

void DotSceneLoader::processNode(TiXmlElement *XMLNode, SceneNode *pParent)
{
	// Construct the node's name
	String name = m_sPrependNode + getAttrib(XMLNode, "name");

	// Create the scene node
	SceneNode *pNode;
	if(name.empty())
	{
		// Let Ogre choose the name
		if(pParent)
			pNode = pParent->createChildSceneNode();
		else
			pNode = mAttachNode->createChildSceneNode();
	}
	else
	{
		// Provide the name
		if(pParent)
			pNode = pParent->createChildSceneNode(name);
		else
			pNode = mAttachNode->createChildSceneNode(name);
	}

	// Process other attributes
	String id = getAttrib(XMLNode, "id");
	bool isTarget = getAttribBool(XMLNode, "isTarget");

	TiXmlElement *pElement;

	// Process position (?)
	pElement = XMLNode->FirstChildElement("position");
	if(pElement)
	{
		pNode->setPosition(parseVector3(pElement));
		pNode->setInitialState();
	}

	// Process rotation (?)
	pElement = XMLNode->FirstChildElement("rotation");
	if(pElement)
	{
		pNode->setOrientation(parseQuaternion(pElement));
		pNode->setInitialState();
	}

	// Process scale (?)
	pElement = XMLNode->FirstChildElement("scale");
	if(pElement)
	{
		pNode->setScale(parseVector3(pElement));
		pNode->setInitialState();
	}

	// Process lookTarget (?)
	pElement = XMLNode->FirstChildElement("lookTarget");
	if(pElement)
		processLookTarget(pElement, pNode);

	// Process trackTarget (?)
	pElement = XMLNode->FirstChildElement("trackTarget");
	if(pElement)
		processTrackTarget(pElement, pNode);

	// Process node (*)
	pElement = XMLNode->FirstChildElement("node");
	while(pElement)
	{
		processNode(pElement, pNode);
		pElement = pElement->NextSiblingElement("node");
	}

	// Process entity (*)
	pElement = XMLNode->FirstChildElement("entity");
	while(pElement)
	{
		processEntity(pElement, pNode);
		pElement = pElement->NextSiblingElement("entity");
	}

	// Process light (*)
	pElement = XMLNode->FirstChildElement("light");
	while(pElement)
	{
		processLight(pElement, pNode);
		pElement = pElement->NextSiblingElement("light");
	}

	// Process camera (*)
	pElement = XMLNode->FirstChildElement("camera");
	while(pElement)
	{
		processCamera(pElement, pNode);
		pElement = pElement->NextSiblingElement("camera");
	}

	// Process particleSystem (*)
	pElement = XMLNode->FirstChildElement("particleSystem");
	while(pElement)
	{
		processParticleSystem(pElement, pNode);
		pElement = pElement->NextSiblingElement("particleSystem");
	}

	// Process billboardSet (*)
	pElement = XMLNode->FirstChildElement("billboardSet");
	while(pElement)
	{
		processBillboardSet(pElement, pNode);
		pElement = pElement->NextSiblingElement("billboardSet");
	}

	// Process plane (*)
	pElement = XMLNode->FirstChildElement("plane");
	while(pElement)
	{
		processPlane(pElement, pNode);
		pElement = pElement->NextSiblingElement("plane");
	}

	pElement = XMLNode->FirstChildElement("trigger");
	while(pElement)
	{
		processTrigger(pElement, pNode);
		pElement = pElement->NextSiblingElement("trigger");
	}

	pElement = XMLNode->FirstChildElement("sound");
	while(pElement)
	{
		processSound(pElement, pNode);
		pElement = pElement->NextSiblingElement("sound");
	}
	// Process userDataReference (?)
	pElement = XMLNode->FirstChildElement("userDataReference");
	if(pElement)
		processUserDataReference(pElement, pNode);
}

void DotSceneLoader::processLookTarget(TiXmlElement *XMLNode, SceneNode *pParent)
{
	//! @todo Is this correct? Cause I don't have a clue actually

	// Process attributes
	String nodeName = getAttrib(XMLNode, "nodeName");

	Node::TransformSpace relativeTo = Node::TS_PARENT;
	String sValue = getAttrib(XMLNode, "relativeTo");
	if(sValue == "local")
		relativeTo = Node::TS_LOCAL;
	else if(sValue == "parent")
		relativeTo = Node::TS_PARENT;
	else if(sValue == "world")
		relativeTo = Node::TS_WORLD;

	TiXmlElement *pElement;

	// Process position (?)
	Vector3 position;
	pElement = XMLNode->FirstChildElement("position");
	if(pElement)
		position = parseVector3(pElement);

	// Process localDirection (?)
	Vector3 localDirection = Vector3::NEGATIVE_UNIT_Z;
	pElement = XMLNode->FirstChildElement("localDirection");
	if(pElement)
		localDirection = parseVector3(pElement);

	// Setup the look target
	try
	{
		if(!nodeName.empty())
		{
			SceneNode *pLookNode = mSceneMgr->getSceneNode(nodeName);
			position = pLookNode->_getDerivedPosition();
		}

		pParent->lookAt(position, relativeTo, localDirection);
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error processing a look target!");
	}
}

void DotSceneLoader::processTrackTarget(TiXmlElement *XMLNode, SceneNode *pParent)
{
	// Process attributes
	String nodeName = getAttrib(XMLNode, "nodeName");

	TiXmlElement *pElement;

	// Process localDirection (?)
	Vector3 localDirection = Vector3::NEGATIVE_UNIT_Z;
	pElement = XMLNode->FirstChildElement("localDirection");
	if(pElement)
		localDirection = parseVector3(pElement);

	// Process offset (?)
	Vector3 offset = Vector3::ZERO;
	pElement = XMLNode->FirstChildElement("offset");
	if(pElement)
		offset = parseVector3(pElement);

	// Setup the track target
	try
	{
		SceneNode *pTrackNode = mSceneMgr->getSceneNode(nodeName);
		pParent->setAutoTracking(true, pTrackNode, localDirection, offset);
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error processing a track target!");
	}
}

void DotSceneLoader::processEntity(TiXmlElement *XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");
	String meshFile = getAttrib(XMLNode, "meshFile");
	String materialFile = getAttrib(XMLNode, "materialFile");
	bool isStatic = getAttribBool(XMLNode, "static", false);;
	bool castShadows = getAttribBool(XMLNode, "castShadows", true);

	// TEMP: Maintain a list of static and dynamic objects
	if(isStatic)
		staticObjects.push_back(name);
	else
		dynamicObjects.push_back(name);

	TiXmlElement *pElement;

	// Process vertexBuffer (?)
	pElement = XMLNode->FirstChildElement("vertexBuffer");
	if(pElement)
		;//processVertexBuffer(pElement);

	// Process indexBuffer (?)
	pElement = XMLNode->FirstChildElement("indexBuffer");
	if(pElement)
		;//processIndexBuffer(pElement);

	// Create the entity
	Entity *pEntity = 0;
	try
	{
		if(m_bPhysics)
		{
			NxOgre::MeshManager* meshManager = NxOgre::MeshManager::getSingleton();
			if(isStatic)
			{
				//convert .mesh name to .nxs
				String phyxName=meshFile;
				for(int i=0;i<4;i++)
				{
					phyxName.pop_back();
				}
				phyxName.append("nxs");
				NxOgre::Mesh* mesh=meshManager->load("ogre://"+phyxName,name);

				Ogre::Vector3 pos = pParent->getPosition();
				Ogre::Quaternion q = pParent->getOrientation();
				NxOgre::Vec3 vec = NxOgre::Vec3::ZERO;
				vec.x=pos.x;
				vec.y=pos.y;
				vec.z=pos.z;

				NxOgre::Quat qu = NxOgre::Quat::IDENTITY;
				qu.w = q.w;
				qu.x = q.x;
				qu.y = q.y;
				qu.z = q.z;
				NxOgre::Matrix44 mat(vec,pParent->getOrientation());
				//add to scene geometry
				m_pPhysScene->createSceneGeometry(NxOgre::TriangleGeometryDescription(mesh),mat);
				//add ogre mesh to viualise
				MeshManager::getSingleton().load(meshFile, m_sGroupName);
				pEntity = mSceneMgr->createEntity(name, meshFile);
				pEntity->setCastShadows(castShadows);

				pParent->attachObject(pEntity);
				if(!materialFile.empty())
					pEntity->setMaterialName(materialFile);
			}else
			{
				if(id != "NO_PHYSX")
				{
					//convert .mesh name to .nxs
					String phyxName=meshFile;
					for(int i=0;i<4;i++)
					{
						phyxName.pop_back();
					}
					phyxName.append("nxs");
					NxOgre::Mesh* mesh=meshManager->load("ogre://"+phyxName,name);

					Critter::BodyDescription bodyDescription;

					pElement = XMLNode->FirstChildElement("Body");
					if(pElement)
					{
						bodyDescription = processBodyDescription(pElement,pParent);
					}else
					{
						//default body attributes
						bodyDescription.mMass = 20.0f;
						bodyDescription.mName = "PhysX"+pParent->getName();
						bodyDescription.mNode = pParent;
					}

					Ogre::Matrix4 final=Ogre::Matrix4::IDENTITY;
					final.makeTransform(pParent->getPosition(),pParent->getScale(),pParent->getOrientation());
					NxOgre::Matrix44 pose=NxOgre::Matrix44::IDENTITY;

					//pose.set(PhysicsSystem::GetSingleton()->convertOgreVec3(final.getTrans()));
					pose.set(PhysicsSystem::GetSingleton()->convertOgreQuat(final.extractQuaternion()));

					Ogre::Vector3 pos = pParent->getPosition();
					NxOgre::Vec3 vec = NxOgre::Vec3::ZERO;
					vec.x=pos.x;
					vec.y=pos.y;
					vec.z=pos.z;

					Ogre::Vector3 Osc=pParent->getScale();
					NxOgre::Vec3 sc=NxOgre::Vec3::ZERO;
					sc.x=Osc.x;
					sc.y=Osc.y;
					sc.z=Osc.z;

					pose.set(vec.x,vec.y,vec.z);

					MeshManager::getSingleton().load(meshFile, m_sGroupName);
					pEntity = mSceneMgr->createEntity(name, meshFile);
					pEntity->setCastShadows(castShadows);

					if(!materialFile.empty())
						pEntity->setMaterialName(materialFile);

					Critter::Body* bod = m_pPhysRenderSys->createBody(NxOgre::ConvexDescription(mesh),pose,pEntity,bodyDescription);
					bod->setGroup(bodyDescription.mGroup);
				}else	//if PHYSX_NO_MESH then just make a Ogre Entity with no physX stuff
				{
					MeshManager::getSingleton().load(meshFile, m_sGroupName);
					pEntity = mSceneMgr->createEntity(name, meshFile);
					pEntity->setCastShadows(castShadows);

					pParent->attachObject(pEntity);
					if(!materialFile.empty())
						pEntity->setMaterialName(materialFile);
				}
			}
		}
		if(isStatic || (!isStatic && !m_bPhysics))
		{
			if(id == "NO_PHYSX")
			{
				MeshManager::getSingleton().load(meshFile, m_sGroupName);
				pEntity = mSceneMgr->createEntity(name, meshFile);
				pEntity->setCastShadows(castShadows);

				pParent->attachObject(pEntity);
				if(!materialFile.empty())
					pEntity->setMaterialName(materialFile);
			}
		}
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error loading an entity!");
	}

	// Process userDataReference (?)
	pElement = XMLNode->FirstChildElement("userDataReference");
	if(pElement)
		processUserDataReference(pElement, pEntity);
}

void DotSceneLoader::processSound(TiXmlElement *XMLNode, SceneNode *pParent)
{
	String name = getAttrib(XMLNode, "name");
	String fileName =	getAttrib(XMLNode, "fileName");
	bool bStreamed = getAttribBool(XMLNode, "streamed",false);
	bool bLooping = getAttribBool(XMLNode, "looping",false);
	float size = getAttribReal(XMLNode,"size",1.0f);

	SoundSystem::GetSingleton()->loadSound(fileName.c_str(),bStreamed);
	SoundNode* sound=0;
	if(name != "")
		sound = SoundNodeManager::GetSingleton()->createSoundNode(name,fileName,bLooping,size);
	else
		sound = SoundNodeManager::GetSingleton()->createSoundNode(fileName,bLooping,size);
	assert(sound);	//if sound is null
	pParent->attachObject(sound);
}

void DotSceneLoader::processTrigger(TiXmlElement *XMLNode, SceneNode *pParent)
{
	String shape = getAttrib(XMLNode,"shape");
	Real size = getAttribReal(XMLNode,"size");
	String luaObj = getAttrib(XMLNode,"luaObj");
	String luaFile = getAttrib(XMLNode,"luaFile");

	TriggerManager::TriggerShape sh;	//shape of trigger volume
	float si;							//size of trigger volume
	luabind::object obj;				//the lua obj
	if(shape == "cube")
		sh = TriggerManager::TriggerShape::Cube;
	else
		sh = TriggerManager::TriggerShape::Sphere;

	si = size;
	LuaScriptManager::GetSingleton()->doFile(luaFile.c_str());
	luabind::object g = luabind::globals(LuaScriptManager::GetSingleton()->getLuaState());	//the states we declare are in global table in Lua
	obj = g[luaObj.c_str()];	//retrieve the state from the Lua global table
	assert(obj.is_valid());		//this should be valid, check for typoes in Lua file
	TriggerManager::GetSingleton()->createTriggerVolume(sh,si,obj,pParent->getPosition());
}

Critter::BodyDescription DotSceneLoader::processBodyDescription(TiXmlElement *XMLNode, SceneNode *pParent)
{
	Real angularDamping =  getAttribReal(XMLNode, "angularDamping",0.05);
	Real linearDamping = getAttribReal(XMLNode, "linearDamping",0.0);
	Real density = getAttribReal(XMLNode, "density",0.0);
	Real mass = getAttribReal(XMLNode, "mass",1.0);
	int group = getAttribInt(XMLNode,"group",0);

	//DynamicRidigBody flags
	bool DisableGravity = getAttribBool(XMLNode,"disableGravity");
	bool FreezePosX = getAttribBool(XMLNode,"freezePosX");
	bool FreezePosY = getAttribBool(XMLNode,"freezePosY");
	bool FreezePosZ = getAttribBool(XMLNode,"freezePosZ");
	bool FreezePos = getAttribBool(XMLNode,"freezePos");
	bool FreezeRotX = getAttribBool(XMLNode,"freezeRotX");
	bool FreezeRotY = getAttribBool(XMLNode,"freezeRotY");
	bool FreezeRotZ = getAttribBool(XMLNode,"freezeRotZ");
	bool FreezeRot = getAttribBool(XMLNode,"freezeRot");

	Critter::BodyDescription body;
	body.mAngularDamping=angularDamping;
	body.mLinearDamping=linearDamping;
	body.mDensity=density;
	body.mMass=mass;
	body.mGroup=group;
	body.mName="PhysX"+pParent->getName();
	body.mNode = pParent;

	if(DisableGravity)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::DisableGravity;
	if(FreezePosX)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezePositionX;
	if(FreezePosY)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezePositionY;
	if(FreezePosZ)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezePositionZ;
	if(FreezePos)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezePosition;
	if(FreezeRotX)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezeRotationX;
	if(FreezeRotY)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezeRotationY;
	if(FreezeRotZ)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezeRotationZ;
	if(FreezeRot)
		body.mDynamicRigidbodyFlags |= NxOgre::DynamicRigidbodyFlags::FreezeRotation;

	return body;
}

void DotSceneLoader::processParticleSystem(TiXmlElement *XMLNode, SceneNode *pParent)
{
	// Process attributes
	String name = getAttrib(XMLNode, "name");
	String id = getAttrib(XMLNode, "id");
	String file = getAttrib(XMLNode, "file");

	// Create the particle system
	try
	{
		ParticleSystem *pParticles = mSceneMgr->createParticleSystem(name, file);
		pParent->attachObject(pParticles);
	}
	catch(Ogre::Exception &/*e*/)
	{
		LogManager::getSingleton().logMessage("[DotSceneLoader] Error creating a particle system!");
	}
}

void DotSceneLoader::processBillboardSet(TiXmlElement *XMLNode, SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processPlane(TiXmlElement *XMLNode, SceneNode *pParent)
{
	//! @todo Implement this
}

void DotSceneLoader::processFog(TiXmlElement *XMLNode)
{
	// Process attributes
	Real expDensity = getAttribReal(XMLNode, "expDensity", 0.001);
	Real linearStart = getAttribReal(XMLNode, "linearStart", 0.0);
	Real linearEnd = getAttribReal(XMLNode, "linearEnd", 1.0);

	FogMode mode = FOG_NONE;
	String sMode = getAttrib(XMLNode, "mode");
	if(sMode == "none")
		mode = FOG_NONE;
	else if(sMode == "exp")
		mode = FOG_EXP;
	else if(sMode == "exp2")
		mode = FOG_EXP2;
	else if(sMode == "linear")
		mode = FOG_LINEAR;

	TiXmlElement *pElement;

	// Process colourDiffuse (?)
	ColourValue colourDiffuse = ColourValue::White;
	pElement = XMLNode->FirstChildElement("colourDiffuse");
	if(pElement)
		colourDiffuse = parseColour(pElement);

	// Setup the fog
	mSceneMgr->setFog(mode, colourDiffuse, expDensity, linearStart, linearEnd);
}

void DotSceneLoader::processSkyBox(TiXmlElement *XMLNode)
{
	// Process attributes
	String material = getAttrib(XMLNode, "material");
	Real distance = getAttribReal(XMLNode, "distance", 5000);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	TiXmlElement *pElement;

	// Process rotation (?)
	Quaternion rotation = Quaternion::IDENTITY;
	pElement = XMLNode->FirstChildElement("rotation");
	if(pElement)
		rotation = parseQuaternion(pElement);

	// Setup the sky box
	mSceneMgr->setSkyBox(true, material, distance, drawFirst, rotation, m_sGroupName);
}

void DotSceneLoader::processSkyDome(TiXmlElement *XMLNode)
{
	// Process attributes
	String material = XMLNode->Attribute("material");
	Real curvature = getAttribReal(XMLNode, "curvature", 10);
	Real tiling = getAttribReal(XMLNode, "tiling", 8);
	Real distance = getAttribReal(XMLNode, "distance", 4000);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	TiXmlElement *pElement;

	// Process rotation (?)
	Quaternion rotation = Quaternion::IDENTITY;
	pElement = XMLNode->FirstChildElement("rotation");
	if(pElement)
		rotation = parseQuaternion(pElement);

	// Setup the sky dome
	mSceneMgr->setSkyDome(true, material, curvature, tiling, distance, drawFirst, rotation, 16, 16, -1, m_sGroupName);
}

void DotSceneLoader::processSkyPlane(TiXmlElement *XMLNode)
{
	// Process attributes
	String material = getAttrib(XMLNode, "material");
	Real planeX = getAttribReal(XMLNode, "planeX", 0);
	Real planeY = getAttribReal(XMLNode, "planeY", -1);
	Real planeZ = getAttribReal(XMLNode, "planeX", 0);
	Real planeD = getAttribReal(XMLNode, "planeD", 5000);
	Real scale = getAttribReal(XMLNode, "scale", 1000);
	Real bow = getAttribReal(XMLNode, "bow", 0);
	Real tiling = getAttribReal(XMLNode, "tiling", 10);
	bool drawFirst = getAttribBool(XMLNode, "drawFirst", true);

	// Setup the sky plane
	Plane plane;
	plane.normal = Vector3(planeX, planeY, planeZ);
	plane.d = planeD;
	mSceneMgr->setSkyPlane(true, plane, material, scale, tiling, drawFirst, bow, 1, 1, m_sGroupName);
}

void DotSceneLoader::processClipping(TiXmlElement *XMLNode)
{
	//! @todo Implement this

	// Process attributes
	Real fNear = getAttribReal(XMLNode, "near", 0);
	Real fFar = getAttribReal(XMLNode, "far", 1);
}

void DotSceneLoader::processLightRange(TiXmlElement *XMLNode, Light *pLight)
{
	// Process attributes
	Real inner = getAttribReal(XMLNode, "inner");
	Real outer = getAttribReal(XMLNode, "outer");
	Real falloff = getAttribReal(XMLNode, "falloff", 1.0);

	// Setup the light range
	pLight->setSpotlightRange(Angle(inner), Angle(outer), falloff);
}

void DotSceneLoader::processLightAttenuation(TiXmlElement *XMLNode, Light *pLight)
{
	// Process attributes
	Real range = getAttribReal(XMLNode, "range");
	Real constant = getAttribReal(XMLNode, "constant");
	Real linear = getAttribReal(XMLNode, "linear");
	Real quadratic = getAttribReal(XMLNode, "quadratic");

	// Setup the light attenuation
	pLight->setAttenuation(range, constant, linear, quadratic);
}

String DotSceneLoader::getAttrib(TiXmlElement *XMLNode, const String &attrib, const String &defaultValue)
{
	if(XMLNode->Attribute(attrib.c_str()))
		return XMLNode->Attribute(attrib.c_str());
	else
		return defaultValue;
}

Real DotSceneLoader::getAttribReal(TiXmlElement *XMLNode, const String &attrib, Real defaultValue)
{
	if(XMLNode->Attribute(attrib.c_str()))
		return StringConverter::parseReal(XMLNode->Attribute(attrib.c_str()));
	else
		return defaultValue;
}

int DotSceneLoader::getAttribInt(TiXmlElement *XMLNode, const String &attrib, int defaultValue)
{
	if(XMLNode->Attribute(attrib.c_str()))
		return StringConverter::parseInt(XMLNode->Attribute(attrib.c_str()));
	else
		return defaultValue;
}

bool DotSceneLoader::getAttribBool(TiXmlElement *XMLNode, const String &attrib, bool defaultValue)
{
	if(!XMLNode->Attribute(attrib.c_str()))
		return defaultValue;

	if(String(XMLNode->Attribute(attrib.c_str())) == "true")
		return true;

	return false;
}

Vector3 DotSceneLoader::parseVector3(TiXmlElement *XMLNode)
{
	return Vector3(
		StringConverter::parseReal(XMLNode->Attribute("x")),
		StringConverter::parseReal(XMLNode->Attribute("y")),
		StringConverter::parseReal(XMLNode->Attribute("z"))
	);
}

Quaternion DotSceneLoader::parseQuaternion(TiXmlElement *XMLNode)
{
	//! @todo Fix this crap!

	Quaternion orientation;

	if(XMLNode->Attribute("qx"))
	{
		orientation.x = StringConverter::parseReal(XMLNode->Attribute("qx"));
		orientation.y = StringConverter::parseReal(XMLNode->Attribute("qy"));
		orientation.z = StringConverter::parseReal(XMLNode->Attribute("qz"));
		orientation.w = StringConverter::parseReal(XMLNode->Attribute("qw"));
	}
	else if(XMLNode->Attribute("axisX"))
	{
		Vector3 axis;
		axis.x = StringConverter::parseReal(XMLNode->Attribute("axisX"));
		axis.y = StringConverter::parseReal(XMLNode->Attribute("axisY"));
		axis.z = StringConverter::parseReal(XMLNode->Attribute("axisZ"));
		Real angle = StringConverter::parseReal(XMLNode->Attribute("angle"));;
		orientation.FromAngleAxis(Ogre::Angle(angle), axis);
	}
	else if(XMLNode->Attribute("angleX"))
	{
		Vector3 axis;
		axis.x = StringConverter::parseReal(XMLNode->Attribute("angleX"));
		axis.y = StringConverter::parseReal(XMLNode->Attribute("angleY"));
		axis.z = StringConverter::parseReal(XMLNode->Attribute("angleZ"));
		//orientation.FromAxes(&axis);
		//orientation.F
	}

	return orientation;
}

ColourValue DotSceneLoader::parseColour(TiXmlElement *XMLNode)
{
	return ColourValue(
		StringConverter::parseReal(XMLNode->Attribute("r")),
		StringConverter::parseReal(XMLNode->Attribute("g")),
		StringConverter::parseReal(XMLNode->Attribute("b")),
		XMLNode->Attribute("a") != NULL ? StringConverter::parseReal(XMLNode->Attribute("a")) : 1
	);
}

String DotSceneLoader::getProperty(const String &ndNm, const String &prop)
{
	for ( unsigned int i = 0 ; i < nodeProperties.size(); i++ )
	{
		if ( nodeProperties[i].nodeName == ndNm && nodeProperties[i].propertyNm == prop )
		{
			return nodeProperties[i].valueName;
		}
	}

	return "";
}

void DotSceneLoader::processUserDataReference(TiXmlElement *XMLNode, Entity *pEntity)
{
	String str = XMLNode->Attribute("id");
	pEntity->setUserAny(Any(str));
}